<template>
	<div class="app-container">
		<!-- 操作工作栏 -->
		<jk-operation-card ref="box1">
			<div class="flex-between-center-wrap">
				<div class="flex-start-center-wrap">
					<el-button
						type="primary"
						plain
						icon="el-icon-upload"
						size="small"
						class="item-gap"
						@click="openImportTable"
					>导入</el-button>
					<!--<right-toolbar :show-search.sync="showSearch" @queryTable="getListRequest"></right-toolbar>-->
				</div>
				<div v-show="showSearch">
					<el-input
						v-model="searchParams.tableName"
						placeholder="请输入表名称"
						clearable
						class="search-bar-item-size2 margin-5-0 item-gap"
						size="small"
						@keyup.enter.native="onSearchBtn"
					/>
					<el-input
						v-model="searchParams.tableComment"
						placeholder="请输入表描述"
						clearable
						class="search-bar-item-size2 margin-5-0 item-gap"
						size="small"
						@keyup.enter.native="onSearchBtn"
					/>
					<el-date-picker
						v-model="searchParams.createTime"
						style="width: 240px"
						value-format="yyyy-MM-dd HH:mm:ss"
						type="daterange"
						range-separator="-"
						start-placeholder="开始日期"
						end-placeholder="结束日期"
						class="search-bar-item-size2 margin-5-0 item-gap"
						size="small"
						:default-time="['00:00:00', '23:59:59']"
					/>
					<el-button type="primary" icon="el-icon-search" size="small" @click="onSearchBtn">搜索</el-button>
					<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
				</div>
			</div>
		</jk-operation-card>

		<!-- 列表 -->
		<jk-card class="margin-top-10">
			<jk-table :data="tableList" :height="tableHeight">
				<vxe-column title="表描述" align="left" field="tableComment" :min-width="120" fixed="left" />
				<vxe-column title="表名称" align="left" field="tableName" :min-width="200" />
				<vxe-column title="实体" align="left" field="className" width="200" />
				<vxe-column title="数据源" align="left" width="80px">
					<template slot-scope="scope">
						<span>{{ dataSourceConfigNameFormat(scope.row) }}</span>
					</template>
				</vxe-column>
				<vxe-column title="创建时间" align="left" field="createTime" width="160"></vxe-column>
				<vxe-column title="更新时间" align="left" field="updateTime" width="160"></vxe-column>
				<vxe-column title="操作" align="center" width="400px" fixed="right">
					<template slot-scope="scope">
						<div class="flex-center">
							<div class="item-gap"><el-button type="default" size="mini" icon="el-icon-delete" @click="onDeleteBtn(scope.row)">删除</el-button></div>
							<div class="item-gap"><el-button type="default" size="mini" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button></div>
							<div class="item-gap"><el-button type="default" size="mini" icon="el-icon-edit" @click="handleEditTable(scope.row)">编辑</el-button></div>
							<div class="item-gap"><el-button type="default" size="mini" icon="el-icon-refresh" @click="handleSynchDb(scope.row)">同步</el-button></div>
							<el-button type="default" size="mini" icon="el-icon-download" @click="handleGenTable(scope.row)">下载</el-button>
						</div>
					</template>
				</vxe-column>
			</jk-table>
			<footer ref="box2" class="flex-end-center margin-top-10">
				<jk-page
					:page-index="searchParams.pageNo"
					:page-sizes="searchParams.pageSizes"
					:page-size="searchParams.pageSize"
					:total="searchParams.count"
					@on-change="onPageChange"
				/>
			</footer>
		</jk-card>
		<!-- 预览界面 -->
		<jk-dialog
			:title="preview.title"
			:dialog-state.sync="preview.open"
			width="90%"
			top="5vh"
			append-to-body
			class="scrollbar"
			:show-close-btn="true"
			:show-confirm-btn="false"
			:show-cancel-btn="false"
			@on-close="onVisibleChangeOfPreview(false)"
			@on-visible-change="onVisibleChangeOfPreview"
		>
			<el-row>
				<el-col :span="7" :style="{ height: `${tableHeight + 20}px`, overflow: 'auto' }">
					<el-tree
						:data="preview.fileTree"
						:expand-on-click-node="false"
						default-expand-all
						highlight-current
						@node-click="handleNodeClick"
					/>
				</el-col>
				<el-col :span="17">
					<el-tabs v-model="preview.activeName" type="border-card">
						<el-tab-pane
							v-for="item in preview.data"
							:key="item.filePath"
							:label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)"
							:name="item.filePath"
						>
							<div :style="{ height: `${tableHeight - 50}px`, overflow: 'auto', padding: '10px 16px', position: 'relative', width: '100%' }">
								<div style="position: sticky; top: 10px;">
									<el-link v-clipboard:copy="item.code" v-clipboard:success="clipboardSuccess" style="float: right;" :underline="false" icon="el-icon-document-copy">复制</el-link>
								</div>
								<pre><code class="hljs" v-html="highlightedCode(item)"></code></pre>
							</div>
						</el-tab-pane>
					</el-tabs>
				</el-col>
			</el-row>
		</jk-dialog>

		<!-- 基于 DB 导入 -->
		<import-table ref="import" @ok="onSearchBtn" />
	</div>
</template>

<script>
    import clipboard from '../../../directive/module/clipboard';
    import { getCodegenTablePage, previewCodegen, downloadCodegen, deleteCodegen,
             syncCodegenFromDB } from '@/api/infra/codegen';

    import importTable from './importTable';
    import { getDataSourceConfigList } from '@/api/infra/dataSourceConfig';
    import calHeight from '../../../mixins/cal-table-height';
    import handlerCache from '../../../mixins/handler-cache';
    import { pageConfig } from '../../../utils/jk/jk-tool';
    export default {
        name: 'Codegen',
        components: { importTable },
        directives: {
            clipboard
        },
        mixins: [calHeight, handlerCache],
        data() {
            return {
                prefix: 'infra:codegen',
                loading: true,
                uniqueId: '',
                tableNames: [],
                showSearch: true,
                total: 0,
                tableList: [],
                dateRange: '',
                searchParams: {
                    count: 0,
                    pageNo: 1,
                    pageSize: pageConfig.pageSize,
                    tableName: undefined,
                    tableComment: undefined,
                    createTime: []
                },
                preview: {
                    open: false,
                    title: '代码预览',
                    fileTree: [],
                    data: {},
                    activeName: ''
                },
                dataSourceConfigs: []
            };
        },
        created() {
            this.getListRequest();
            getDataSourceConfigList().then(res => {
                this.dataSourceConfigs = res.data.res;
            });
        },
        activated() {
            const time = this.$route.query.t;
            if (time != null && time !== this.uniqueId) {
                this.uniqueId = time;
                this.resetQuery();
            }
        },
        methods: {
            onPageChange(pageIndex, pageSize) {
                this.searchParams.pageNo = pageIndex;
                this.searchParams.pageSize = pageSize;
                this.getListRequest();
            },
            onVisibleChangeOfPreview(e) {
                this.$set(this.preview, 'open', e);
            },
            /** 查询表集合 */
            getListRequest() {
                this.loading = true;
                getCodegenTablePage(this.searchParams).then(res => {
                    this.loading = false;
                    if (res.data.status === 200) {
                        this.tableList = res.data.res;
                        this.searchParams.count = res.data.count;
                    }
                });
            },
            /** 搜索按钮操作 */
            onSearchBtn() {
                this.searchParams.pageNo = 1;
                this.getListRequest();
            },
            /** 生成代码操作 */
            handleGenTable(row) {
                downloadCodegen(row.id).then(res => {
                    this.$download.zip(res.data, 'codegen-' + row.tableName + '.zip');
                });
            },
            /** 同步数据库操作 */
            handleSynchDb(row) {
                // 基于 DB 同步
                const tableName = row.tableName;
                this.$confirm('确认要强制同步"' + tableName + '"表结构吗？').then(() => {
                    return syncCodegenFromDB(row.id);
                }).then(() => {
                    this.$message('同步成功');
                }).catch(() => {});
            },
            /** 打开导入表弹窗 */
            openImportTable() {
                this.$refs.import.show();
            },
            /** 重置按钮操作 */
            resetQuery() {
                this.$resetForm(this, 'queryForm');
                this.onSearchBtn();
            },
            /** 预览按钮 */
            handlePreview(row) {
                previewCodegen(row.id).then(res => {
                    this.preview.data = res.data.res;
                    const files = this.handleFiles(res.data.res);
                    this.preview.fileTree = this.getTree({ res: files }, 'id', 'parentId', 'children', '/'); // "/" 为根节点
                    this.preview.activeName = res.data.res[0].filePath;
                    this.preview.open = true;
                });
            },
            getTree(data, id, parentId, children, rootId) {
                id = id || 'id';
                parentId = parentId || 'parentId';
                children = children || 'children';
                rootId = rootId || Math.min.apply(Math, data.res.map(item => {
                    return item[parentId];
                })) || 0;
                // 对源数据深度克隆
                const cloneData = JSON.parse(JSON.stringify(data.res));
                // 循环所有项
                const treeData = cloneData.filter(father => {
                    const branchArr = cloneData.filter(child => {
                        // 返回每一项的子级数组
                        return father[id] === child[parentId];
                    });
                    branchArr.length > 0 ? father.children = branchArr : '';
                    // 返回第一层
                    return father[parentId] === rootId;
                });
                return treeData !== '' ? treeData : data;
            },
            /** 复制代码成功 */
            clipboardSuccess() {
                this.$message('复制成功');
            },
            /** 生成 files 目录 **/
            handleFiles(datas) {
                const exists = {}; // key：file 的 id；value：true
                const files = [];
                // 遍历每个元素
                for (const data of datas) {
                    let paths = data.filePath.split('/');
                    let fullPath = ''; // 从头开始的路径，用于生成 id
                    // 特殊处理 java 文件
                    if (paths[paths.length - 1].indexOf('.java') >= 0) {
                        const newPaths = [];
                        for (let i = 0; i < paths.length; i++) {
                            let path = paths[i];
                            if (path !== 'java') {
                                newPaths.push(path);
                                continue;
                            }
                            newPaths.push(path);
                            // 特殊处理中间的 package，进行合并
                            let tmp;
                            while (i < paths.length) {
                                path = paths[i + 1];
                                if (path === 'controller'
                                    || path === 'convert'
                                    || path === 'dal'
                                    || path === 'enums'
                                    || path === 'service'
                                    || path === 'vo' // 下面三个，主要是兜底。可能考虑到有人改了包结构
                                    || path === 'mysql'
                                    || path === 'dataobject') {
                                    break;
                                }
                                tmp = tmp ? tmp + '.' + path : path;
                                i++;
                            }
                            if (tmp) {
                                newPaths.push(tmp);
                            }
                        }
                        paths = newPaths;
                    }
                    // 遍历每个 path， 拼接成树
                    for (let i = 0; i < paths.length; i++) {
                        // 已经添加到 files 中，则跳过
                        const oldFullPath = fullPath;
                        // 下面的 replaceAll 的原因，是因为上面包处理了，导致和 tabs 不匹配，所以 replaceAll 下
                        fullPath = fullPath.length === 0 ? paths[i] : fullPath.replaceAll('.', '/') + '/' + paths[i];
                        if (exists[fullPath]) {
                            continue;
                        }
                        // 添加到 files 中
                        exists[fullPath] = true;
                        files.push({
                            id: fullPath,
                            label: paths[i],
                            parentId: oldFullPath || '/' // "/" 为根节点
                        });
                    }
                }
                return files;
            },
            highlightedCode(item) {
                // const vmName = key.substring(key.lastIndexOf("/") + 1, key.indexOf(".vm"));
                // var language = vmName.substring(vmName.indexOf(".") + 1, vmName.length);
                var language = item.filePath.substring(item.filePath.lastIndexOf('.') + 1);
                // const result = hljs.highlight(language, item.code || '', true);
                return item.code;
            },
            /** 节点单击事件 **/
            handleNodeClick(data, node) {
                if (node && !node.isLeaf) {
                    return false;
                }
                // 判断，如果非子节点，不允许选中
                this.preview.activeName = data.id;
            },
            /** 修改按钮操作 */
            handleEditTable(row) {
                const tableId = row.id;
                const tableName = row.tableName || this.tableNames[0];
                const params = { pageNum: this.searchParams.pageNum };
                this.$tab.openPage('修改[' + tableName + ']生成配置', '/codegen/edit/' + tableId, params);
            },
            /** 删除按钮操作 */
            onDeleteBtn(row) {
                const tableIds = row.id;
                this.$confirm('是否确认删除表名称为"' + row.tableName + '"的数据项?').then(() => {
                    return deleteCodegen(tableIds);
                }).then(() => {
                    this.getListRequest();
                    this.$tipsBar(this, 'delete');
                }).catch(() => {});
            },
            // 数据源配置的名字
            dataSourceConfigNameFormat(row, column) {
                for (const config of this.dataSourceConfigs) {
                    if (row.dataSourceConfigId === config.id) {
                        return config.name;
                    }
                }
                return '未知【' + row.leaderUserId + '】';
            }
        }
    };
</script>
